/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*                                                                    *
*        ***************************************************         *
*        *©2021-2031 LINUO Corporation All rights reserved *         *
*        ***************************************************         *
*                                                                    *
* FileName    : vpss.c                                               *
*                                                                    *
* Author      : linus                                                *
*                                                                    *
* Email       : luoyaojun@sina.com                                   *
*                                                                    *
* Date        : 2024-3-27                                            *
*                                                                    *
* Description :                                                      *
*                                                                    *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "common.h"
#include "h_register.h"
#include "h_vpss.h"
#include "vpss.h"

static HT_S32 rockchip_vpss_default_config(struct rockchip_vpss *plt_vpss)
{
	HT_S32 ret = -1;
	
	ret = ht_pthread_init(&plt_vpss->pthread, "rockchip_vpss");

	if (ret)
	{
		printf("pthread init faild %d\n", ret);
		return -2;
	}

	return 0;
}

static struct rockchip_vpss *rockchip_vpss_priv_list(struct rockchip_vpss *plt_vpss, HT_S32 vpss_grp, HT_S32 vpss_chn)
{
	struct rockchip_vpss_priv *priv = plt_vpss->vpss_priv;
	HT_U32 item = 0;

	item = (vpss_grp>0)?vpss_grp*VPSS_MAX_CHN_NUM+vpss_chn:vpss_chn;

	return (struct rockchip_vpss *)(priv+item);
}

static PIXEL_FORMAT_E rockchip_pixel_fmt(HT_PIXEL_FORMAT fmt)
{
    PIXEL_FORMAT_E ret_fmt = RK_FMT_YUV420SP;

    switch (fmt)
    {
    case HT_FMT_RGB888:
        ret_fmt = RK_FMT_RGB888;
        break;
	case HT_FMT_YUV420SP:
		ret_fmt = RK_FMT_YUV420SP;
		break;
    default:
        ret_fmt = RK_FMT_YUV420SP;
        break;
    }

    return ret_fmt;
}

static RK_S32 rockchip_vpss_group_exit(struct ht_vpss *pvpss, HT_U32 vpss_grp)
{
    RK_S32 s32Ret = -1;

    s32Ret = RK_MPI_VPSS_StopGrp(vpss_grp);
    if (s32Ret != RK_SUCCESS)
    {
        return s32Ret;
    }

    s32Ret = RK_MPI_VPSS_DestroyGrp(vpss_grp);
    if (s32Ret != RK_SUCCESS)
    {
        return s32Ret;
    }

    return s32Ret;
}

static RK_S32 rockchip_vpss_chn_init(struct ht_vpss *pvpss, HT_U32 vpss_grp, HT_U32 vpss_chn, struct resolution *res,
                                     HT_PIXEL_FORMAT fmt, HT_U32 u32Depth)
{
    RK_S32 s32Ret = RK_SUCCESS;
    VPSS_CHN_ATTR_S stVpssChnAttr;

	memset(&stVpssChnAttr, 0, sizeof(VPSS_CHN_ATTR_S));

	/**
	**	PAST模式(VPSS_CHN_MODE_PASSTHROUGH)：
	**	在绑定VO时使用，将会把处理工作放于VO中一并处理，不会带来额外开销，预览、回放时建议设置为此模式。
	**
	**	USER模式(VPSS_CHN_MODE_USER)：
	**	用户需要手动获取通道处理输出图像时设置，会带来性能开销。
	*/
    stVpssChnAttr.enChnMode 					= VPSS_CHN_MODE_USER;
    stVpssChnAttr.enCompressMode 				= COMPRESS_MODE_NONE;
    stVpssChnAttr.enDynamicRange 				= DYNAMIC_RANGE_SDR8;
    stVpssChnAttr.enPixelFormat 				= rockchip_pixel_fmt(fmt);
    stVpssChnAttr.stFrameRate.s32SrcFrameRate 	= -1;
    stVpssChnAttr.stFrameRate.s32DstFrameRate 	= -1;
    stVpssChnAttr.u32Width 						= res->width;
    stVpssChnAttr.u32Height 					= res->height;
//	stVpssChnAttr.u32FrameBufCnt 				= 1;
	
    printf("ht_vpss_enable_chn grp = %d, chn = %d\n", vpss_grp, vpss_chn);

    stVpssChnAttr.u32Depth = u32Depth;

    s32Ret = RK_MPI_VPSS_SetChnAttr(vpss_grp, vpss_chn, &stVpssChnAttr);
    if (s32Ret != RK_SUCCESS)
    {
        printf("RK_MPI_VPSS_SetChnAttr error %08x!\n", s32Ret);
        return s32Ret;
    }

    s32Ret = RK_MPI_VPSS_GetChnAttr(vpss_grp, vpss_chn, &stVpssChnAttr);
    if (s32Ret != RK_SUCCESS)
    {
        printf("RK_MPI_VPSS_GetChnAttr error %08x!\n", s32Ret);
        return s32Ret;
    }

    s32Ret = RK_MPI_VPSS_EnableChn(vpss_grp, vpss_chn);
    if (s32Ret != RK_SUCCESS)
    {
        printf("RK_MPI_VPSS_EnableChn error %08x!\n", s32Ret);
        return s32Ret;
    }

    return s32Ret;
}

static HT_S32 rockchip_vpss_chn_exit(__unused struct ht_vpss *pvpss, HT_U32 vpss_grp, HT_U32 vpss_chn)
{
	return RK_MPI_VPSS_DisableChn(vpss_grp, vpss_chn);
}

static RK_S32 rockchip_vpss_init(struct ht_vpss *pvpss, RK_U32 vpss_grp, HT_PIXEL_FORMAT fmt)
{
    RK_S32 s32Ret = RK_SUCCESS;
    RK_S32 ret = -1;
	VPSS_GRP_ATTR_S grp_attr;
//	VPSS_MOD_PARAM_S pstModParam;

	memset(&grp_attr, 0, sizeof(VPSS_GRP_ATTR_S));

	grp_attr.u32MaxW 						= 8192;
	grp_attr.u32MaxH 						= 8192;
	grp_attr.enDynamicRange 				= DYNAMIC_RANGE_SDR8;
	grp_attr.enPixelFormat					= rockchip_pixel_fmt(fmt);
	grp_attr.enCompressMode					= COMPRESS_MODE_NONE;
	grp_attr.stFrameRate.s32SrcFrameRate 	= -1;
	grp_attr.stFrameRate.s32DstFrameRate 	= -1;
	
    s32Ret = RK_MPI_VPSS_CreateGrp(vpss_grp, &grp_attr);
    if (s32Ret != RK_SUCCESS)
        return s32Ret;

#ifdef RV1126_RV1109
	//	rv1126没有GPU，默认使用GPU时会导致段错误
    RK_MPI_VPSS_SetVProcDev(vpss_grp, VIDEO_PROC_DEV_RGA);
#else
    RK_MPI_VPSS_SetVProcDev(vpss_grp, VIDEO_PROC_DEV_GPU);
#endif

    s32Ret = RK_MPI_VPSS_StartGrp(vpss_grp);
    if (s32Ret != RK_SUCCESS)
        return s32Ret;

    return s32Ret;
}

HT_S32 rockchip_chn_start_get_frame(struct ht_vpss *pvpss, HT_U32 vpss_grp, HT_U32 vpss_chn)
{

}

HT_S32 rockchip_chn_stop_get_frame(struct ht_vpss *pvpss, HT_U32 vpss_grp, HT_U32 vpss_chn)
{

}

HT_S32 rockchip_vpss_chn_get_frame(struct ht_vpss *pvpss, HT_U32 vpss_grp, HT_U32 vpss_chn, ht_vpss_chn_get_frame_cb cb, void *user)
{
	VIDEO_FRAME_INFO_S frameOut = {0};
	HT_S32 ret = -1;
	HT_S32 fd = -1;
	
	ret = RK_MPI_VPSS_GetChnFrame(vpss_grp, vpss_chn, &frameOut, 200);

	fd = RK_MPI_MB_Handle2Fd(frameOut.stVFrame.pMbBlk);
	
	if (cb)
		cb(vpss_grp, vpss_chn, &fd, &frameOut);

	if (!ret)
	RK_MPI_VPSS_ReleaseChnFrame(vpss_grp, vpss_chn, &frameOut);
}


HT_S32 rockchip_vpss_chn_get_info(struct ht_vpss *pvpss, HT_U32 vpss_grp, HT_U32 vpss_chn, HT_S32 *fd, HT_S32 *width, HT_S32 *height)
{
	HT_S32 chn_fd = 0;
	VIDEO_FRAME_INFO_S frameOut = {0};
	VPSS_CHN_ATTR_S vpss_chn_attr;

	RK_MPI_VPSS_GetChnFrame(vpss_grp, vpss_chn, &frameOut, -1);
	*fd = RK_MPI_MB_Handle2Fd(frameOut.stVFrame.pMbBlk);
	
//	chn_fd = RK_MPI_VPSS_GetChnFd(vpss_grp, vpss_chn);

	RK_MPI_VPSS_GetChnAttr(vpss_grp, vpss_chn, &vpss_chn_attr);

	*width = vpss_chn_attr.u32Width;
	*height = vpss_chn_attr.u32Height;

	return 0;
}


static struct ht_vpss_ops g_vpss_ops = {
    .vpss_grp_init 					= rockchip_vpss_init,
	.vpss_grp_exit 					= rockchip_vpss_group_exit,
//	.vpss_grp_start_get_frame		=,
	.vpss_chn_get_frame				= rockchip_vpss_chn_get_frame,
    .vpss_chn_init 					= rockchip_vpss_chn_init,
    .vpss_chn_start_get_frame 		= rockchip_chn_start_get_frame,
    .vpss_chn_stop_get_frame 		= rockchip_chn_stop_get_frame,
	.vpss_chn_get_info				= rockchip_vpss_chn_get_info,
	.vpss_chn_exit 					= rockchip_vpss_chn_exit,
};
	
static HT_S32 rockchip_vpss_grp_rt_set_abs_crop(struct ht_vpss *pvpss, HT_S32 vpss_grp, HT_U32 enable, struct rect *prect)
{
	VPSS_CROP_INFO_S stCropInfo;
	HT_S32 s32Ret = -1;
	
    s32Ret = RK_MPI_VPSS_GetGrpCrop(vpss_grp, &stCropInfo);
    if (s32Ret != RK_SUCCESS)
	{
        RK_LOGE("RK_MPI_VPSS_GetGrpCrop failed with %#x!", s32Ret);
        return s32Ret;
    }

	stCropInfo.bEnable 				= !!enable;
	stCropInfo.enCropCoordinate 	= VPSS_CROP_ABS_COOR;
    stCropInfo.stCropRect.s32X 		= prect->s32X;
    stCropInfo.stCropRect.s32Y 		= prect->s32Y;
    stCropInfo.stCropRect.u32Width 	= prect->res.width;
    stCropInfo.stCropRect.u32Height = prect->res.height;

    s32Ret = RK_MPI_VPSS_SetGrpCrop(vpss_grp, &stCropInfo);
    if (s32Ret != RK_SUCCESS)
	{
        RK_LOGE("RK_MPI_VPSS_SetGrpCrop failed with %#x!", s32Ret);
        return s32Ret;
    }

	printf("rockchip_vpss_grp_rt_set_abs_crop status = %d\n", enable);
	
    return s32Ret;
}


static struct ht_vpss_rtconfig g_vpss_rtconfig = {

	.vpss_grp_rt_set_abs_crop = rockchip_vpss_grp_rt_set_abs_crop,
};

__init static RK_S32 rockchip_vpss_register(void)
{
    RK_S32 ret = -1;
    struct rockchip_vpss *plt_vpss = (struct rockchip_vpss *)calloc(1, sizeof(struct rockchip_vpss));
    struct ht_vpss *pvpss = NULL;

    if (!plt_vpss)
        return -1;
	
	ret = rockchip_vpss_default_config(plt_vpss);
	if (ret)
		return ret;

    pvpss = &plt_vpss->m_vpss;

	pvpss->m_id = HT_ID_VPSS;
	
    pvpss->ops = &g_vpss_ops;
	
	pvpss->rt_config = &g_vpss_rtconfig;
	
    ht_vpss_module_register(pvpss);

    return ret;
}
